/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#ifndef __ATC_AIRSPACE_HDR__
#define __ATC_AIRSPACE_HDR__


#include <qobject.h>
//Added by qt3to4:
#include <Q3PointArray>
#include "atc_types.h"
#include "aircraft_data.h"
#include <qregion.h>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>


#define AIRCRAFT_MAP      std::map<        std::string, AircraftAgent * >
#define AIRCRAFT_MAP_PAIR std::pair< const std::string, AircraftAgent * >
#define QREGIONLIST	      std::vector< QRegion >

#define CONFLICT_PAIR     std::pair<std::string, std::string>
#define CONFLICT_MAP      std::map<CONFLICT_PAIR, bool>


namespace atc {

	//
	// atc classes
	//

	class  AircraftAgent;
	struct AreaDefinition;


	//
	// atc::airspace_error
	//
	struct airspace_error : public std::runtime_error{
		airspace_error(const std::string& msg)
			:std::runtime_error(msg)
		{}
	};

    //
    // atc::Airspace
    //

    class Airspace : public QObject {
		Q_OBJECT
    public: // construction
        Airspace();
        ~Airspace();
	public: // builder interface
		void set_hdoms( double hdoms ) { _hdoms = hdoms; }
		void set_vdoms( double vdoms ) { _vdoms = vdoms; }
		void add_aircraft( AircraftAgent * );
		void define_sector( const AreaDefinition & );
		void add_non_sector( const AreaDefinition & );
	public:
		void initialize();
		bool point_in_sector( const Point & ) const;
	public:
		AIRCRAFT_MAP::iterator begin() { return _aircraft.begin(); }
		AIRCRAFT_MAP::iterator   end() { return _aircraft.end();   }
    public slots:
		void advance( int );
	private:
		Q3PointArray& area_points( const AreaDefinition &, Q3PointArray & );
		double bearing( QPoint, QPoint ) const;  
	signals:
		void advanced();
		void event_recorded( KeyValues & );
		void sig_conflict_detected( const std::string &, const std::string & );
		void sig_missed_acceptance();
	private:
		AIRCRAFT_MAP _aircraft;
		CONFLICT_MAP _conflicts;
		QRegion     _sector;
		QREGIONLIST _nonsector;
		double _hdoms;
		double _vdoms;

	//
	// iterators
	//
	public:
		typedef AIRCRAFT_MAP::iterator iterator;

	//
	// functors
	//
	private: 
		//
		// AdvancePosition
		//
		class AdvancePosition 
			  : public std::unary_function< AIRCRAFT_MAP_PAIR, void > {
		public:
			AdvancePosition( int ms ) : _time( ms ) {}
			void operator ()( AIRCRAFT_MAP_PAIR ) const; 
		private:
			const int _time;
		};

		//
		// DetectConflicts
		//
		class DetectConflicts 
			  : public std::unary_function< AIRCRAFT_MAP_PAIR, void > {
		public:
			DetectConflicts( AIRCRAFT_MAP *, double, double );
			void operator ()( AIRCRAFT_MAP_PAIR ) const;
		private:
			AIRCRAFT_MAP *_map;
			double _hdoms;
			double _vdoms;
		};

		friend class DetectConflicts;

		//
		// atc::Airspace::IsConflicted
		//
		class IsConflicted
			  : public std::unary_function< AIRCRAFT_MAP_PAIR, bool > {
		public:
			IsConflicted( AircraftAgent *, double, double );
			bool operator ()( AIRCRAFT_MAP_PAIR ) const;
		private:
			AircraftAgent *_ac;
			double         _hdoms;
			double         _vdoms;
		};

		//
		// atc::Airspace::InitialControlState
		//
		class InitialControlState
			  : public std::unary_function< AIRCRAFT_MAP_PAIR, void > {
		public:
			InitialControlState( const Airspace * as ) : _airspace( as ) {}
			void operator ()( AIRCRAFT_MAP_PAIR ) const;
		private:
			const Airspace *_airspace;
		};

		//
		// atc::Airspace::UpdateControlState
		//
		class UpdateControlState
			  : public std::unary_function< AIRCRAFT_MAP_PAIR, void > {
		public:
			UpdateControlState( const Airspace * as ) : _airspace( as ) {}
			void operator ()( AIRCRAFT_MAP_PAIR ) const;
		private:
			ControlState updated_control( AircraftAgent * ) const;
		private:
			const Airspace *_airspace;
		};
	};

	//
	// typedefs
	//
	typedef AIRCRAFT_MAP      ACAgentMap;
	typedef AIRCRAFT_MAP_PAIR ACAgentMapPair;
	typedef QREGIONLIST       QRegionList;
	typedef CONFLICT_PAIR     ConflictPair;
	typedef CONFLICT_MAP      ConflictMap;
};


#undef AIRCRAFT_MAP
#undef AIRCRAFT_MAP_PAIR
#undef QREGIONLIST
#undef CONFLICT_PAIR
#undef CONFLICT_MAP


#endif
